/*
 * ImageControler.cpp
 *
 *  Created on: 08.08.2012
 *      Author: Caffeine
 */

#include "ImageControler.h"

#include "../Utils.h"
#include "../core/Environment.h"
#include <thread/IThread.h>
#include <log/Log.h>
#include <thread/ITask.h>
#include <thread/IMutex.h>
#include <thread/ITask.h>
#include <thread/ITaskMutexUnlock.h>

#include <log/Log.h>

namespace irr{
namespace image{

class IImageCombineParalel:public irr::thread::ITask{
private:
	ImageControler*image;
	irr::thread::ITask*task;
public:
	IImageCombineParalel(irr::thread::ITask*t,ImageControler*i){
		task=t;
		image=i;
		task->grab();
		image->grab();
		grab();
	}
	virtual void run(){
		if (irr::thread::isMainThread())
			LOG("smartUseAllLayout in MAIN");
		else
			LOG("smartUseAllLayout in OTHER");
		image->smartUseAllLayout();
		task->run();
		task->drop();
		image->drop();
		drop();
	}
};

class ImageBinderTask:public irr::thread::ITaskMutexUnlock{
private:
	irr::image::ImageControler*image;
	bool lock;
public:
	ImageBinderTask(irr::image::ImageControler*i,bool l,irr::thread::IMutex*m):irr::thread::ITaskMutexUnlock(m){
		image=i;
		lock=l;
		image->grab();

	}
	virtual void run(){
		if (lock)
			image->lock();
		else
			image->unlock();
		image->drop();
	}
};

class ImageLoaderTask:public irr::thread::ITaskMutexUnlock{
private:
	irr::image::ImageControler*image;
	bool load;
public:
	ImageLoaderTask(irr::image::ImageControler*i,bool l,irr::thread::IMutex*m):irr::thread::ITaskMutexUnlock(m){
		image=i;
		load=l;
		image->grab();

	}
	virtual void run(){
		mutex->lock();
		if (load)
			image->load();
		else
			image->unload();
		image->drop();
		mutex->unlock();
	}
};

ImageControler::ImageControler() {
	texture=0;
	image=0;
	path="";

	locked=irr::thread::createRecursiveMutex();
	loaded=irr::thread::createRecursiveMutex();
}

ImageControler::ImageControler(irr::io::path p){
	texture=0;
	image=0;
	path="";
	setPath(p);
	locked=irr::thread::createRecursiveMutex();
	loaded=irr::thread::createRecursiveMutex();
}

ImageControler::~ImageControler() {
	unload();
	for (irr::u32 i=0;i<list.size();i++){
		list[i]->drop();
		list.erase(i);
	}
	list.clear();
}

void ImageControler::setPath(irr::io::path p){
	if (p==""){
		LOGE("Path to texture is empty!");
		exit(0);
		return;
	}
	bool loaded=isLoaded();
	if (loaded)
		unload();
	path=p;
	LOG("set image \"%s\"",p.c_str());
	if (loaded)
		load();
}

irr::io::path ImageControler::getPath(){
	return path;
}

void ImageControler::load(){

	unload();
	if (!irr::core::Environment::getFileSystem()->existFile(getPath())){
		LOGW("Can't find texture \"%s\"",getPath().c_str());
		exit(0);
	}
	loaded->lock();
	texture=irr::core::Environment::getDriver()->getTexture(getPath());
	texture->grab();
	loaded->unlock();
	unlock();

}

void ImageControler::unload(){
	loaded->lock();
	if (image)
		image->drop();
	if (texture)
		texture->drop();
	image=0;
	texture=0;
	loaded->unlock();
}

irr::u32 ImageControler::addLayout(ImageControlerRecord*icr){
	list.push_back(icr);
	icr->grab();
	return list.size()-1;
}

ImageControlerRecord*ImageControler::addLayout(irr::io::path p,irr::core::vector2di pos){
	ImageControlerRecord*res=new ImageControlerRecord();
	res->setPath(p);
	res->setPosition(pos);
	addLayout(res);
	res->drop();
	return res;
}

ImageControlerRecord*ImageControler::getLayout(irr::u32 index){
	return list[index];
}

void ImageControler::removeLayout(irr::u32 index){
	LOG("removeLayout \"%s\"",list[index]->getPath().c_str());
	list[index]->drop();
	list.erase(index);
}

bool ImageControler::isLoaded(){
	return texture!=0 || image!=0;
}

void ImageControler::lock(){
	if (isLocked())
		return;
	if (!image){
		LOGE("Image \"%s\" is NULL!",getPath().c_str());
		exit(0);
	}
	locked->lock();
	if (texture){
		LOGW("Texture \"%s\" is not NULL, but is must be NULL",getPath().c_str());
		texture->drop();
	}
	//smartUseAllLayout();
	irr::core::Environment::getDriver()->writeImageToFile(image,"test.png");
	texture=irr::utils::ImageTexture(image,irr::core::Environment::getDriver(),"1234.png");
	image->drop();
	image=0;
	locked->unlock();
}

void ImageControler::unlock(){
	if (!isLocked())
		return;
	if (!texture){
		LOGE("Texture \"%s\" is NULL",getPath().c_str());
		exit(0);
	}
	if (image){
		image->drop();
		LOGW("Image \"%s\" is not NULL, but is must be NULL",getPath().c_str());
	}
	image=irr::utils::TextureImage(texture,irr::core::Environment::getDriver());
	texture->drop();
	texture=0;
	clearUsedLayout();
}

bool ImageControler::isLocked(){
	return texture!=0;
}


bool ImageControler::attach(irr::io::path p,irr::core::vector2di pos){
	irr::video::IImage*im=irr::core::Environment::getDriver()->createImageFromFile(p);
	bool res=attach(im,pos);
	im->drop();
	return res;
}

bool ImageControler::attach(irr::video::IImage*i,irr::core::vector2di pos){
	if (isLocked()){
		LOGE("Can't attach: image is locked!");
		return false;
	}
	i->grab();
	irr::utils::copyImageWithAlpha(i,image,pos);
	i->drop();
	return true;
}

bool ImageControler::attach(irr::video::ITexture*i,irr::core::vector2di pos){
	irr::video::IImage*im=irr::utils::TextureImage(i,irr::core::Environment::getDriver());
	bool res=attach(im,pos);
	im->drop();
	return res;
}
bool ImageControler::attach_origenal(irr::core::recti rect){
	LOGE("Not supported");
	exit(0);
}

void ImageControler::useLayout(irr::u32 index){
	if (!attach(list[index]->getPath(),list[index]->getPosition())){
		LOGW("Layout #%u not atteched",index);
		list[index]->setAteched(true);
	}
}

void ImageControler::smartUseAllLayout(){
	for (irr::u32 i=0;i<getLayoutCount();i++)
		if (!list[i]->isAtechd())
			useLayout(i);
}

void ImageControler::smartUseAllLayout_unsync(irr::thread::ITask*done){

	IImageCombineParalel*a=new IImageCombineParalel(done,this);
	irr::thread::IThread*thread=irr::core::Environment::getDevice()->createTaskThread(a);
	a->drop();
	//IImageCombineParalel*thread=new IImageCombineParalel(done,this);
	thread->start();
	thread->drop();
}

void ImageControler::clearUsedLayout(){
	for (irr::u32 i=0;i<getLayoutCount();i++)
		list[i]->setAteched(false);
}

irr::s32 ImageControler::indexOfPath(irr::io::path p){
	for (irr::u32 i=0;i<getLayoutCount();i++)
		if (list[i]->getPath()==p)
			return i;
	return -1;
}

void ImageControler::removeLayout(irr::io::path p){
	irr::s32 index=indexOfPath(p);
	if (index>=0)
		removeLayout(index);
}

irr::u32 ImageControler::getLayoutCount(){
	return list.size();
}

irr::video::ITexture*ImageControler::getTexture(){
	if (!isLocked())
		lock();
	return texture;
}

}
}
